/**
 * Created by ${PRODUCT_NAME}.
 * User: skylerparr
 * Date: 12/26/10
 * Time: 10:13 PM
 * To change this template use File | Settings | File Templates.
 */
package com.thoughtorigin.loader {
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;

import flash.events.IOErrorEvent;

import flash.net.URLLoader;

import org.flexunit.asserts.assertEquals;
import org.flexunit.asserts.assertTrue;
import org.flexunit.async.Async;
import org.mockito.integrations.any;
import org.mockito.integrations.between;
import org.mockito.integrations.callOriginal;
import org.mockito.integrations.given;
import org.mockito.integrations.mock;
import org.mockito.integrations.verify;

[RunWith("org.mockito.integrations.flexunit4.MockitoClassRunner")]
[Mock(type="flash.net.URLLoader")]
[Mock(type="flash.events.EventDispatcher")]
public class URLLoadertemTest {
    private var _loader: TestableLoaderItem;
    private var _mockLoader: URLLoader;
    private var _dispatcher: IEventDispatcher;
    private var _url: String = "sampleUrl";

    [Before]
    public function setup(): void {
        _loader = new TestableLoaderItem(_url);
        _mockLoader = mock(URLLoader);
        _loader._mockloader = _mockLoader;
        _dispatcher = mock(EventDispatcher);
        _loader._dispatcher = _dispatcher;
    }

    [After]
    public function tearDown(): void {
        _loader = null;
        _mockLoader = null;
        _dispatcher = null;
    }

    [Test(async)]
    public function shouldLoadContent(): void {
        assertEquals(_url, _loader.url);

        var async: Function = Async.asyncHandler(this, function(e: Event, o: Object):void {
            verify(between(1,1)).that(_mockLoader.load(any()));
        },100)

        _loader.addEventListener(Event.COMPLETE, async);

        given(_dispatcher.dispatchEvent(any())).will(callOriginal());
        given(_dispatcher.addEventListener(any(), any())).will(callOriginal());
        given(_mockLoader.load(any())).will(new EventAnswer(_dispatcher, new Event(Event.COMPLETE)))

        _loader.start();
    }

    [Test(async)]
    public function shouldHandleSecurityEvent(): void {
        assertEquals(_url, _loader.url);

        var async: Function = Async.asyncHandler(this, function(e: Event, o: Object):void {
            assertTrue(true);
        },100)

        _loader.addEventListener(IOErrorEvent.NETWORK_ERROR, async);

        given(_dispatcher.dispatchEvent(any())).will(callOriginal());
        given(_dispatcher.addEventListener(any(), any())).will(callOriginal());
        given(_mockLoader.load(any())).will(new EventAnswer(_dispatcher, new IOErrorEvent(IOErrorEvent.NETWORK_ERROR)))

        _loader.start();
    }
    [Test(async)]
    public function shouldHandleIOError(): void {
        assertEquals(_url, _loader.url);

        var async: Function = Async.asyncHandler(this, function(e: Event, o: Object):void {
            assertTrue(true);
        },100)

        _loader.addEventListener(IOErrorEvent.IO_ERROR, async);

        given(_dispatcher.dispatchEvent(any())).will(callOriginal());
        given(_dispatcher.addEventListener(any(), any())).will(callOriginal());
        given(_mockLoader.load(any())).will(new EventAnswer(_dispatcher, new IOErrorEvent(IOErrorEvent.IO_ERROR)))

        _loader.start();
    }
    [Test(async)]
    public function shouldHandleDiskError(): void {
        assertEquals(_url, _loader.url);

        var async: Function = Async.asyncHandler(this, function(e: Event, o: Object):void {
            assertTrue(true);
        },100)

        _loader.addEventListener(IOErrorEvent.DISK_ERROR, async);

        given(_dispatcher.dispatchEvent(any())).will(callOriginal());
        given(_dispatcher.addEventListener(any(), any())).will(callOriginal());
        given(_mockLoader.load(any())).will(new EventAnswer(_dispatcher, new IOErrorEvent(IOErrorEvent.DISK_ERROR)))

        _loader.start();
    }
    [Test(async)]
    public function shouldHandleVerifyError(): void {
        assertEquals(_url, _loader.url);

        var async: Function = Async.asyncHandler(this, function(e: Event, o: Object):void {
            assertTrue(true);
        },100)

        _loader.addEventListener(IOErrorEvent.VERIFY_ERROR, async);

        given(_dispatcher.dispatchEvent(any())).will(callOriginal());
        given(_dispatcher.addEventListener(any(), any())).will(callOriginal());
        given(_mockLoader.load(any())).will(new EventAnswer(_dispatcher, new IOErrorEvent(IOErrorEvent.VERIFY_ERROR)))

        _loader.start();
    }

    [Test(async)]
    public function shouldNotStartTheLoaderTwice(): void {
        assertEquals(_url, _loader.url);

        var async: Function = Async.asyncHandler(this, function(e: Event, o: Object):void {
            verify(between(1,1)).that(_mockLoader.load(any()));
        },100)

        _loader.addEventListener(Event.COMPLETE, async);

        given(_dispatcher.dispatchEvent(any())).will(callOriginal());
        given(_dispatcher.addEventListener(any(), any())).will(callOriginal());
        given(_mockLoader.load(any())).will(new EventAnswer(_dispatcher, new Event(Event.COMPLETE)))

        _loader.start();
        _loader.start();
        _loader.start();
    }
}
}


import com.thoughtorigin.loader.URLLoaderItem;

import flash.events.IEventDispatcher;
import flash.net.URLLoader;

class TestableLoaderItem extends URLLoaderItem {

    public var _mockloader: URLLoader;
    public var _dispatcher: IEventDispatcher;

    public function TestableLoaderItem(url:String) {
        super(url);
    }

    override protected function createLoader(): * {
        return _mockloader;
    }

    override public function get contentDispatcher():IEventDispatcher {
        return _dispatcher;
    }
}

import flash.events.Event;

import flash.utils.setTimeout;

import org.mockito.api.Answer;

class EventAnswer implements Answer {

    private var _dispatcher: IEventDispatcher;
    private var _eventToDispatch: Event;

    public function EventAnswer(dispatcher: IEventDispatcher, eventToDispatch: Event) {
        _dispatcher = dispatcher
        _eventToDispatch = eventToDispatch;
    }

    public function give():* {
        setTimeout(function(): void {
            _dispatcher.dispatchEvent(_eventToDispatch);
        }, 20);
    }
}
